﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.MissionViews.Singleplayer.FormationIndicatorMissionView
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Library;
using TaleWorlds.MountAndBlade.View.Screens;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.MissionViews.Singleplayer
{
  public class FormationIndicatorMissionView : MissionView
  {
    private FormationIndicatorMissionView.Indicator[,] _indicators;
    private Mission mission;
    private bool _isEnabled;

    public override void AfterStart()
    {
      base.AfterStart();
      this.mission = Mission.Current;
      this._indicators = new FormationIndicatorMissionView.Indicator[this.mission.Teams.Count, 9];
      for (int index1 = 0; index1 < this.mission.Teams.Count; ++index1)
      {
        for (int index2 = 0; index2 < 9; ++index2)
          this._indicators[index1, index2] = new FormationIndicatorMissionView.Indicator()
          {
            missionScreen = this.MissionScreen
          };
      }
    }

    private GameEntity CreateBannerEntity(Formation formation)
    {
      GameEntity empty = GameEntity.CreateEmpty(this.mission.Scene);
      empty.EntityFlags |= EntityFlags.NoOcclusionCulling;
      uint num1 = 4278190080;
      uint num2 = !formation.Team.IsPlayerAlly ? 2144798212U : 2130747904U;
      empty.AddMultiMesh(MetaMesh.GetCopy("billboard_unit_mesh"));
      empty.GetFirstMesh().Color = uint.MaxValue;
      Material formationMaterial = Material.GetFromResource("formation_icon").CreateCopy();
      if (formation.Team != null)
      {
        Banner banner = formation.Captain != null ? formation.Captain.Origin.Banner : formation.Team.Banner;
        if (banner != null)
        {
          Action<Texture> setAction = (Action<Texture>) (tex => formationMaterial.SetTexture(Material.MBTextureType.DiffuseMap2, tex));
          banner.GetTableauTextureLarge(setAction);
        }
        else
        {
          Texture fromResource = Texture.GetFromResource("plain_red");
          formationMaterial.SetTexture(Material.MBTextureType.DiffuseMap2, fromResource);
        }
      }
      else
      {
        Texture fromResource = Texture.GetFromResource("plain_red");
        formationMaterial.SetTexture(Material.MBTextureType.DiffuseMap2, fromResource);
      }
      int vectorArgument2 = (int) formation.FormationIndex % 4;
      empty.GetFirstMesh().SetMaterial(formationMaterial);
      empty.GetFirstMesh().Color = num2;
      empty.GetFirstMesh().Color2 = num1;
      empty.GetFirstMesh().SetVectorArgument(0.0f, 1f, (float) vectorArgument2, 1f);
      return empty;
    }

    private int GetFormationTeamIndex(Formation formation)
    {
      return this.mission.Teams.Count <= 2 || formation.Team != this.mission.AttackerAllyTeam && formation.Team != this.mission.DefenderAllyTeam ? (int) formation.Team.Side : (this.mission.Teams.Count == 3 ? 2 : (formation.Team == this.mission.DefenderAllyTeam ? 2 : 3));
    }

    public override void OnMissionScreenTick(float dt)
    {
      this.OnMissionTick(dt);
      bool flag;
      if (this.Input.IsGameKeyDown(5))
      {
        flag = false;
        this._isEnabled = false;
      }
      else
        flag = false;
      IEnumerable<Formation> first = this.mission.Teams.SelectMany<Team, Formation>((Func<Team, IEnumerable<Formation>>) (t => (IEnumerable<Formation>) t.FormationsIncludingEmpty));
      if (flag)
      {
        IEnumerable<Formation> second = this.mission.Teams.SelectMany<Team, Formation>((Func<Team, IEnumerable<Formation>>) (t => t.FormationsIncludingEmpty.Where<Formation>((Func<Formation, bool>) (f => f.CountOfUnits > 0))));
        foreach (Formation formation in second)
        {
          int formationTeamIndex = this.GetFormationTeamIndex(formation);
          FormationIndicatorMissionView.Indicator indicator = this._indicators[formationTeamIndex, (int) formation.FormationIndex];
          WorldPosition medianPosition = formation.QuerySystem.MedianPosition;
          indicator.DetermineIndicatorState(dt, medianPosition.GetGroundVec3());
          if ((NativeObject) indicator.indicatorEntity == (NativeObject) null)
          {
            if (indicator.indicatorVisible)
            {
              GameEntity bannerEntity = this.CreateBannerEntity(formation);
              bannerEntity.SetFrame(ref indicator.indicatorFrame);
              bannerEntity.SetVisibilityExcludeParents(true);
              this._indicators[formationTeamIndex, (int) formation.FormationIndex].indicatorEntity = bannerEntity;
              bannerEntity.SetAlpha(0.0f);
              this._indicators[formationTeamIndex, (int) formation.FormationIndex].indicatorAlpha = 0.0f;
            }
          }
          else
          {
            if (indicator.indicatorEntity.IsVisibleIncludeParents() != indicator.indicatorVisible)
            {
              if (!indicator.indicatorVisible)
              {
                if ((double) indicator.indicatorAlpha > 0.0)
                {
                  indicator.indicatorAlpha -= 0.01f;
                  if ((double) indicator.indicatorAlpha < 0.0)
                    indicator.indicatorAlpha = 0.0f;
                  indicator.indicatorEntity.SetAlpha(indicator.indicatorAlpha);
                }
                else
                  indicator.indicatorEntity.SetVisibilityExcludeParents(indicator.indicatorVisible);
              }
              else
                indicator.indicatorEntity.SetVisibilityExcludeParents(indicator.indicatorVisible);
            }
            if (indicator.indicatorVisible && (double) indicator.indicatorAlpha < 1.0)
            {
              indicator.indicatorAlpha += 0.01f;
              if ((double) indicator.indicatorAlpha > 1.0)
                indicator.indicatorAlpha = 1f;
              indicator.indicatorEntity.SetAlpha(indicator.indicatorAlpha);
            }
            if (!indicator._isMovingTooFast && indicator.indicatorEntity.IsVisibleIncludeParents())
              indicator.indicatorEntity.SetFrame(ref indicator.indicatorFrame);
          }
        }
        foreach (Formation formation in first.Except<Formation>(second))
        {
          if (formation.FormationIndex >= FormationClass.NumberOfRegularFormations)
            break;
          FormationIndicatorMissionView.Indicator indicator = this._indicators[this.GetFormationTeamIndex(formation), (int) formation.FormationIndex];
          if ((NativeObject) indicator.indicatorEntity != (NativeObject) null && indicator.indicatorEntity.IsVisibleIncludeParents())
          {
            indicator.indicatorEntity.SetVisibilityExcludeParents(false);
            indicator.indicatorVisible = false;
          }
        }
      }
      else
      {
        if (!this._isEnabled)
          return;
        foreach (Formation formation in first)
        {
          FormationIndicatorMissionView.Indicator indicator = this._indicators[this.GetFormationTeamIndex(formation), (int) formation.FormationIndex];
          if (indicator != null && (NativeObject) indicator.indicatorEntity != (NativeObject) null)
          {
            indicator.indicatorAlpha = 0.0f;
            indicator.indicatorEntity.SetVisibilityExcludeParents(false);
          }
        }
        this._isEnabled = false;
      }
    }

    public class Indicator
    {
      public MissionScreen missionScreen;
      public bool indicatorVisible;
      public MatrixFrame indicatorFrame;
      public bool firstTime = true;
      public GameEntity indicatorEntity;
      public Vec3 nextIndicatorPosition;
      public Vec3 prevIndicatorPosition;
      public float indicatorAlpha = 1f;
      private float _drawIndicatorElapsedTime;
      private const float IndicatorExpireTime = 0.5f;
      private bool _isSeenByPlayer = true;
      internal bool _isMovingTooFast;

      private Vec3? GetCurrentPosition()
      {
        if (Mission.Current.MainAgent != null)
          return new Vec3?(Mission.Current.MainAgent.AgentVisuals.GetGlobalFrame().origin + new Vec3(z: 1f));
        return (NativeObject) this.missionScreen.CombatCamera != (NativeObject) null ? new Vec3?(this.missionScreen.CombatCamera.Position) : new Vec3?();
      }

      public void DetermineIndicatorState(float dt, Vec3 position)
      {
        Mission current = Mission.Current;
        Vec3? currentPosition = this.GetCurrentPosition();
        if (!currentPosition.HasValue)
        {
          this.indicatorVisible = false;
        }
        else
        {
          if (this.firstTime)
          {
            this.prevIndicatorPosition = position;
            this.nextIndicatorPosition = position;
            this.firstTime = false;
          }
          Vec3 v;
          if ((double) this.nextIndicatorPosition.Distance(this.prevIndicatorPosition) / 0.5 > 30.0)
          {
            v = position;
            this._isMovingTooFast = true;
          }
          else
            v = Vec3.Lerp(this.prevIndicatorPosition, this.nextIndicatorPosition, MBMath.ClampFloat(this._drawIndicatorElapsedTime / 0.5f, 0.0f, 1f));
          float num = currentPosition.Value.Distance(v);
          if ((double) this._drawIndicatorElapsedTime < 0.5)
          {
            this._drawIndicatorElapsedTime += dt;
          }
          else
          {
            this.prevIndicatorPosition = this.nextIndicatorPosition;
            this.nextIndicatorPosition = position;
            this._isSeenByPlayer = (double) num < 60.0 && ((double) num < 15.0 || current.Scene.CheckPointCanSeePoint(currentPosition.Value, position) || current.Scene.CheckPointCanSeePoint(currentPosition.Value + new Vec3(z: 2f), position + new Vec3(z: 2f)));
            this._drawIndicatorElapsedTime = 0.0f;
          }
          if (!this._isSeenByPlayer)
          {
            float scaleAmount = MBMath.ClampFloat(num * 0.02f, 1f, 10f) * 3f;
            MatrixFrame identity = MatrixFrame.Identity with
            {
              origin = v
            };
            identity.origin.z += scaleAmount * 0.75f;
            identity.rotation.ApplyScaleLocal(scaleAmount);
            this.indicatorFrame = identity;
            if (this._isMovingTooFast)
            {
              if ((NativeObject) this.indicatorEntity != (NativeObject) null && this.indicatorEntity.IsVisibleIncludeParents())
              {
                this.indicatorVisible = false;
              }
              else
              {
                this._isMovingTooFast = false;
                this.indicatorVisible = true;
              }
            }
            else
              this.indicatorVisible = true;
          }
          else
          {
            this.indicatorVisible = false;
            if (this._isMovingTooFast || !((NativeObject) this.indicatorEntity != (NativeObject) null) || !this.indicatorEntity.IsVisibleIncludeParents())
              return;
            float scaleAmount = MBMath.ClampFloat(num * 0.02f, 1f, 10f) * 3f;
            MatrixFrame identity = MatrixFrame.Identity with
            {
              origin = v
            };
            identity.origin.z += scaleAmount * 0.75f;
            identity.rotation.ApplyScaleLocal(scaleAmount);
            this.indicatorFrame = identity;
          }
        }
      }
    }
  }
}
